//==========================================================================
// Copyright (c) 2000-2008,  Elastos, Inc.  All Rights Reserved.
//==========================================================================
#include <ddk.h>
#include <bvd1bd.h>
#include "xllp_mmc.h"
#include "xllp_common.h"
#include <bulverde.h>
#include <Bvd1.h>
#include <BVD_UDC_Bits.h>

#include "SDBusDriver.h"
#include "SDClient.h"
extern CSDClient g_SDCard;
extern void dumpregs(P_XLLP_MMC_T pMmc);


SD_API_STATUS CSDBusDriver::WaitForSingle(UInt32 val)
{
    UInt32 dtmp;
    while( ( (m_pvMMCReg->MMC_I_REG) & val ) == 0) {
        dtmp = m_pvMMCReg->MMC_STAT;
        /* Check for TIME OUT on Receive Data */
        if ( dtmp & XLLP_STAT_TORD ) {
            return SD_API_STATUS_DATA_TIMEOUT;
        }
        else if ( dtmp & XLLP_STAT_FLASHERR ) {
            return SD_API_STATUS_DATA_TIMEOUT;
        }
        else if ( dtmp & XLLP_STAT_CRCWRERR ) {
            return SD_API_STATUS_WD_CRC_ERROR;
        }
        /* Check for CRC read error */
        else if ( dtmp & XLLP_STAT_CRCRDERR ) {
            return SD_API_STATUS_RD_CRC_ERROR;
        }
    }
//    dumpregs(m_pvMMCReg);
//    kprintf("***************************************\n");
    return SD_API_STATUS_SUCCESS;
}

Boolean CSDBusDriver::stopMMCClock(void)
{
    return XllpMmcStopClock(m_pvMMCReg);
}

Boolean CSDBusDriver::startMMCClock(void)
{
	return XllpMmcStartClock(m_pvMMCReg);
}

Boolean CSDBusDriver::SetClockRate(XLLP_MMC_CLKRATE Rate, Boolean ClkOn)
{
    return XllpMmcSetUpClock(m_pvMMCReg, Rate, (XLLP_BOOL_T)ClkOn);
}


SD_API_STATUS CSDBusDriver::SetSDCardIdleState()
{
    Boolean RetVal;
    XllpMmcSdSetupCmd( m_pvMMCReg,
                       XLLP_MMC_SPICMD0,  //go idle state
					   0xFFFFFFFF,        //don't care
					   XLLP_MMC_RESTOBITS,//at least 74 clocks, now set max 0x7f
					   XLLP_FALSE );          //Idle status, set 1 bit bus
	RetVal = XllpMmcSdStatus(m_pvMMCReg, XLLP_STAT_ENDCMDRES,0x20000, XLLP_TRUE);
    if (!RetVal) {
        DEBUGCHK(_DBGSD,kprintf("SD/MMC go idle state failed!\n"));
        return SD_API_STATUS_UNSUCCESSFUL;
    }
	M_Delay(10);
	DEBUGCHK(_SUCSD,kprintf("SD/MMC go idle state Succeeded!\n"));
	return SD_API_STATUS_SUCCESS;
}

SD_API_STATUS CSDBusDriver::CheckCardBusy(UInt32 TimeOut)
{
    UInt32 dStatus;
    while (TimeOut--) {
        dStatus = m_pvMMCReg->MMC_STAT;
        if ((dStatus & DONE_PROG_RDWR) || (dStatus & DONE_WDATA_XFER) ) {
            return SD_API_STATUS_SUCCESS;
        }
    }
    return SD_API_STATUS_CARD_IS_BUSY;
}


SD_API_STATUS CSDBusDriver::SDCardResponseAndAnalysis_X(
                                    PSD_COMMAND_RESPONSE   pResponse )
{

    UInt32  statusInfo;
    UInt8  *respBuff;
    SD_API_STATUS RetVal;

    if (NoResponse == pResponse->ResponseType) {
        return SD_API_STATUS_SUCCESS;
    }
    RetVal = XllpMmcXtractResp(m_pvMMCReg, \
        (unsigned short *)(pResponse->ResponseBuffer), 0x20000);

    if (RetVal) {
        DEBUGCHK(_DBGSD,kprintf(">>>XllpMmcXtractResp Failed : %08x<<<\n", RetVal));
//        dumpregs(m_pvMMCReg);
        return RetVal;
    }
    else {
        int xx;
        DEBUGCHK(_DBGSD,kprintf("Response Content:\n"));
        xx = (pResponse->ResponseType == ResponseR2) ? 17 : 6;
        for(int i = 0; i < xx; i++) {
            DEBUGCHK(_DBGSD,kprintf("%02x ", pResponse->ResponseBuffer[i]));
        }
        DEBUGCHK(_DBGSD,kprintf("\n"));
    }

    statusInfo = 0;
    respBuff = pResponse->ResponseBuffer;
    if (pResponse->ResponseType == ResponseR6) {
        statusInfo  = (UInt32)(respBuff[3] & 0x1F);//Card Status bits 8 ~ 12
        statusInfo <<= 8;
        statusInfo |= (UInt32)(respBuff[4] & 0xFF);//Card Status bits 0 ~ 7
        if (respBuff[3] & 0x80) {//Card Status bits 23
            statusInfo |= XLLP_BIT_23;
        }
        if (respBuff[3] & 0x40) {//Card Status bits 22
            statusInfo |= XLLP_BIT_22;
        }
        if (respBuff[3] & 0x20) {//Card Status bits 19
            statusInfo |= XLLP_BIT_19;
        }
        statusInfo |= (respBuff[3] & 0xE0);//Card Status bits 23,22,19
    }
    else if (pResponse->ResponseType == ResponseR1) {    /* Get the RAW MMC status */
        statusInfo  = (UInt32)(respBuff[1] & 0xFF);
        statusInfo <<= 8;
        statusInfo |= (UInt32)(respBuff[2] & 0xFF);
        statusInfo <<= 8;
        statusInfo |= (UInt32)(respBuff[3] & 0xFF);
        statusInfo <<= 8;
        statusInfo |= (UInt32)(respBuff[4] & 0xFF);
    }
    else {//Other Response doesn't have status Info
        M_Delay(5);
        goto __Exit;
    }

    /* Check status for error. Convert RAW status to driver error code */
    DEBUGCHK(_DBGSD, kprintf("CURRENT_STATE : %02x\n", (statusInfo>>9) & 0xF));
    DEBUGCHK(_DBGSD, kprintf("statusInfo : %08x\n", statusInfo));

    if (statusInfo & SD_STATUS_OUT_OF_RANGE)
        return  SD_API_STATUS_OUT_OF_RANGE;

    if (statusInfo & SD_STATUS_ADDRESS_ERROR)
        return  SD_API_STATUS_ADDRESS_ERROR;

    if (statusInfo & SD_STATUS_BLOCK_LEN_ERROR)
        return  SD_API_STATUS_DATA_LENGTH_ERROR;

    if (statusInfo & SD_STATUS_ERASE_SEQ_ERROR)
        return  SD_API_STATUS_ERASE_SEQ_ERROR;

    if (statusInfo & SD_STATUS_ERASE_PARAM)
        return  SD_API_STATUS_ERASE_PARAM;

    if (statusInfo & SD_STATUS_WP_VIOLATION)
        return  SD_API_STATUS_WP_VIOLATION;

    if (statusInfo & SD_STATUS_COM_CRC_ERROR)
        return SD_API_STATUS_COM_CRC_ERROR;

    if (statusInfo & SD_STATUS_ILLEGAL_COMMAND)
        return  SD_API_STATUS_COMUNC_ILLEG_COM;

    if (statusInfo & SD_STATUS_CARD_ECC_FAILED)
        return  SD_API_STATUS_CARD_ECC_FAILED;

    if (statusInfo & SD_STATUS_CC_ERROR)
        return  SD_API_STATUS_INTERFACE_ERROR;

    if (statusInfo & SD_STATUS_ERROR)
        return  SD_API_STATUS_ERROR;

    if (statusInfo & SD_STATUS_UNDERRUN)
        return  SD_API_STATUS_UNDERRUN;

    if (statusInfo & SD_STATUS_OVERRUN)
        return  SD_API_STATUS_OVERRUN;

    if (statusInfo & SD_STATUS_CID_CSD_OVERWRITE)
        return  SD_API_STATUS_CIDCSD_OVERWRITE;

    if (statusInfo & SD_STATUS_WP_ERASE_SKIP)
        return  SD_API_STATUS_WP_ERASE_SKIP;

    if (statusInfo & SD_STATUS_CARD_ECC_DISABLED)
        return  SD_API_STATUS_CARD_ECC_DISABLED;

    if (statusInfo & SD_STATUS_ERASE_RESET)
        return  SD_API_STATUS_ERASE_RESET;


    if (statusInfo & SD_STATUS_CARD_IS_LOCKED)
        return  SD_API_STATUS_CARD_IS_LOCKED;

    if (statusInfo & SD_STATUS_LOCK_UNLOCK_FAILED)
        return  SD_API_STATUS_LOCK_UNLOCK_FAILED;

__Exit:
    return SD_API_STATUS_SUCCESS;

}


SD_API_STATUS CSDBusDriver::SDCardBusPrepareRequest_X(
                                             XLLP_MMC_CMD  Cmd,
                                             UInt32         Arg,
                                             UInt32         noBlocks)
{
	if( (Cmd == XLLP_MMC_CMD11) ||
		(Cmd == XLLP_MMC_SPICMD17) ||
		(Cmd == XLLP_MMC_CMD18) ||
		(Cmd == XLLP_SD_ACMD13 ) ||
		(Cmd == XLLP_SD_ACMD51) ||
  		(Cmd == XLLP_MMC_CMD20) ||
		(Cmd == XLLP_MMC_SPICMD24) ||
		(Cmd == XLLP_MMC_CMD25) ) {
	if(Cmd == XLLP_SD_ACMD13)
	 	 XllpMmcSdSetupXCmd(m_pvMMCReg, (XLLP_INT32_T)(DEFAULT_BLK_LENGTH >> 3), (XLLP_INT32_T)(DEFAULT_BLK_LENGTH >> 3));
   	else
   		if(Cmd == XLLP_SD_ACMD51) {
   			 XllpMmcSdSetupXCmd(m_pvMMCReg, (XLLP_INT32_T)8, (XLLP_INT32_T)8);
   			}
   		else {
  			 XllpMmcSdSetupXCmd(m_pvMMCReg, (XLLP_INT32_T)(noBlocks * 512), (XLLP_INT32_T)512);
	    }
	}

    XllpMmcSdSetupCmd(m_pvMMCReg, Cmd, Arg, XLLP_MMC_RESTOBITS, (XLLP_BOOL_T)g_SDCard.m_4Dbus);

    return SD_API_STATUS_SUCCESS;
}



SD_API_STATUS CSDBusDriver::SDCardBusRequestAndResponse_X(
                                                XLLP_MMC_CMD           Command,
                                                UInt32                  Argument,
                                                PSD_COMMAND_RESPONSE   pResponse,
                                                UInt32                  NumBlocks,
                                                UInt32                  BlockSize,
                                                PUInt8                 pBuffer )
{
    SD_API_STATUS RetVal = SD_API_STATUS_SUCCESS;
    if (Command == XLLP_MMC_SPICMD55) {
        m_pvMMCReg->MMC_RESTO = XLLP_MMC_RESTOBITS;
    	m_pvMMCReg->MMC_CMD   = XLLP_MMC_SPICMD55;
    	m_pvMMCReg->MMC_ARGH  = g_SDCard.SD_RCA;
    	m_pvMMCReg->MMC_ARGL  = 0xffff;
    	m_pvMMCReg->MMC_CMDAT = XLLP_MMC_MMCSPIR1 | XLLP_MMC_CMDAT_BUSY;
    }
    else {
        RetVal = SDCardBusPrepareRequest_X(
                                       Command,
                                       Argument,
                                       NumBlocks);

        if (SD_API_FAILED(RetVal)) {
            DEBUGCHK(_DBGSD, \
            kprintf("SDCardBusPrepareRequest_X Command %08x Failed : %08x\n", \
                                    Command, RetVal));
            goto __Exit;
        }
        DEBUGCHK(_SUCSD, \
        kprintf("SDCardBusPrepareRequest_X Command %08x Succeeded : %08x\n", \
                                    Command, RetVal));
    }

    RetVal = SDCardResponseAndAnalysis_X(pResponse);
    if (SD_API_FAILED(RetVal)) {
//        dumpregs(m_pvMMCReg);
        DEBUGCHK(_DBGSD, \
        kprintf("SDCardResponseAndAnalysis_X Command %08x Failed : %08x\n", \
                                    Command, RetVal));
        goto __Exit;
    }
    DEBUGCHK(_SUCSD, \
    kprintf("SDCardResponseAndAnalysis_X Command %08x Succeeded : %08x\n", \
                                    Command, RetVal));
    if ( pBuffer ) {
        if ( (Command == XLLP_MMC_SPICMD13) || (Command == XLLP_SD_ACMD51) ) {
            RetVal = SDCardDataReceive(pBuffer, BlockSize, NumBlocks);
        }
        else if ( (Command == XLLP_MMC_CMD26) ||
                  (Command == XLLP_MMC_SPICMD27) ) {
            RetVal = SDCardDataXmit(pBuffer, BlockSize, NumBlocks);
        }
    }

__Exit:
    return RetVal;
}

SD_API_STATUS CSDBusDriver::SDCardSendAppCmd_X( XLLP_MMC_CMD         Command,
                                                UInt32                Argument,
                                                PSD_COMMAND_RESPONSE pResponse,
                                                UInt32                NumBlocks,
                                                UInt32                BlockSize,
                                                PUInt8               pBlockBuffer )
{
    SD_COMMAND_RESPONSE Res;
    SD_API_STATUS RetVal;
    memset(&Res, 0, sizeof(SD_COMMAND_RESPONSE));
    Res.ResponseType = ResponseR1;

    RetVal = SDCardBusRequestAndResponse_X(
                        XLLP_MMC_SPICMD55,
                        g_SDCard.SD_RCA,
                        &Res,
                        0,
                        0,
                        NULL);

    if (SD_API_FAILED(RetVal)) {
//        dumpregs(m_pvMMCReg);
        DEBUGCHK(_DBGSD, kprintf("XLLP_MMC_SPICMD55 Failed : %08x\n", RetVal));
        goto __Exit;
    }
    DEBUGCHK(_SUCSD, kprintf("XLLP_MMC_SPICMD55 Succeeded : %08x\n", RetVal));
    RetVal = SDCardBusRequestAndResponse_X(
                                 Command,
                                 Argument,
                                 pResponse,
                                 NumBlocks,
                                 BlockSize,
                                 pBlockBuffer);
    if (SD_API_FAILED(RetVal)) {
        DEBUGCHK(_DBGSD, kprintf("APPCMD : %08x Failed %08x\n", Command ,RetVal));
    }

__Exit:
    return RetVal;
}

SD_API_STATUS CSDBusDriver::SDCardReadBlock_X( XLLP_MMC_CMD         Command,
                                               UInt32                Argument,
                                               PSD_COMMAND_RESPONSE pResponse,
                                               UInt32                NumBlocks,
                                               UInt32                BlockSize,
                                               PUInt8               pBlockBuffer )
{
    SD_API_STATUS RetVal ;

    RetVal = SDCardBusRequestAndResponse_X( Command,
                                            Argument,
                                            pResponse,
                                            NumBlocks,
                                            BlockSize,
                                            pBlockBuffer);

    if (SD_API_FAILED(RetVal)) {
        DEBUGCHK(_DBGSD, kprintf("SDCardReadBlock_X : %08x Failed %08x\n", Command ,RetVal));
        goto __Exit;
    }
    RetVal = SDCardDataReceive(pBlockBuffer, BlockSize, NumBlocks);

    if (SD_API_FAILED(RetVal)) {
        DEBUGCHK(_DBGSD, kprintf("SDCardDataReceive : %08x Failed %08x\n", Command ,RetVal));
    }

    if ( XLLP_MMC_CMD18 == Command ) {
        RetVal = SDCardBusRequestAndResponse_X( XLLP_MMC_CMD12,
                                                0xFFFFFFFF,
                                                pResponse,
                                                0,
                                                0,
                                                NULL);

        if (SD_API_FAILED(RetVal)) {
            DEBUGCHK(_DBGSD, kprintf("Stop Transmission : %08x Failed %08x\n", Command ,RetVal));
            goto __Exit;
        }
        RetVal = CheckCardBusy(0x2000000);
    }

__Exit:
    return RetVal;
}



SD_API_STATUS CSDBusDriver::SDCardWriteBlock_X( XLLP_MMC_CMD         Command,
                                                UInt32                Argument,
                                                PSD_COMMAND_RESPONSE pResponse,
                                                UInt32                NumBlocks,
                                                UInt32                BlockSize,
                                                PUInt8               pBlockBuffer)
{
    SD_API_STATUS RetVal ;

    RetVal = SDCardBusRequestAndResponse_X( Command,
                                            Argument,
                                            pResponse,
                                            NumBlocks,
                                            BlockSize,
                                            pBlockBuffer);

    if (SD_API_FAILED(RetVal)) {
        DEBUGCHK(_DBGSD, kprintf("SDCardWriteBlock_X : %08x Failed %08x\n", Command ,RetVal));
        goto __Exit;
    }

    RetVal = SDCardDataXmit(pBlockBuffer, BlockSize, NumBlocks);

    if (SD_API_FAILED(RetVal)) {
        DEBUGCHK(_DBGSD, kprintf("SDCardDataXmit : %08x Failed %08x\n", Command ,RetVal));
    }

    if (XLLP_MMC_CMD25 == Command) {
        RetVal = SDCardBusRequestAndResponse_X( XLLP_MMC_CMD12,
                                                0xFFFFFFFF,
                                                pResponse,
                                                0,
                                                0,
                                                NULL);

        if (SD_API_FAILED(RetVal)) {
            DEBUGCHK(_DBGSD, kprintf("Stop Transmission : %08x Failed %08x\n", Command ,RetVal));
            goto __Exit;
        }
        RetVal = CheckCardBusy(0x2000000);
    }
__Exit:
    return RetVal;
}

//#pragma optimize( "", off )

SD_API_STATUS CSDBusDriver::SDCardDataReceive( UInt8 *dBuf,
                                               UInt32 dataLength,
                                               UInt32 noBlocks)
{
    UInt8 *pBuf;
	UInt32  dLength, i, alignment;
    SD_API_STATUS RetVal = SD_API_STATUS_SUCCESS;
    volatile UInt8 *pMMC_RX_Fifo = (volatile UInt8*)&(m_pvMMCReg->MB_RXFIFO);
	pBuf	= (UInt8 *)dBuf;

	m_pvMMCReg->MMC_I_MASK &= ~0x20;
	for (i=0; i<noBlocks; i++) {
	    dLength = dataLength;
		while (dLength) {
			alignment = ((UInt32)pBuf) & 0x03;
			// If the buffer not 32-bit aligned, we need to align the buffers, then continue with 32-bit copies
			if ((alignment == 1) || (alignment == 5)) {
				if (dLength >= 32) {
    				RetVal = WaitForSingle(0x20);
                    if (SD_API_FAILED(RetVal)) {
                        goto __Exit;
                    }
					*pBuf					= *pMMC_RX_Fifo;			// 1 Byte
					*(UInt16 *)(pBuf + 1)	= *(volatile UInt16 *)pMMC_RX_Fifo;	// 2 BYTES
					*(UInt32 *)(pBuf + 3)	= *(volatile UInt32 *)pMMC_RX_Fifo;	// 4 BYTES
					*(UInt32 *)(pBuf + 7)	= *(volatile UInt32 *)pMMC_RX_Fifo;	// 4 BYTES
					*(UInt32 *)(pBuf + 0xb)	= *(volatile UInt32 *)pMMC_RX_Fifo;	// 4 BYTES
					*(UInt32 *)(pBuf + 0xf) = *(volatile UInt32 *)pMMC_RX_Fifo;	// 4 BYTES
					*(UInt32 *)(pBuf + 0x13)= *(volatile UInt32 *)pMMC_RX_Fifo;	// 4 BYTES
					*(UInt32 *)(pBuf + 0x17)= *(volatile UInt32 *)pMMC_RX_Fifo;	// 4 BYTES
					*(UInt32 *)(pBuf + 0x1b)= *(volatile UInt32 *)pMMC_RX_Fifo;	// 4 BYTES
					*(pBuf + 0x1f)			= *pMMC_RX_Fifo;			// 1 Byte
					pBuf += 32;
					dLength-= 32;
				}
				else {
				    RetVal = WaitForSingle(0x20);
                    if (SD_API_FAILED(RetVal)) {
                        goto __Exit;
                    }
					while (dLength > 0)	{
						*pBuf++ = *pMMC_RX_Fifo;
						dLength--;
					}
				}
			}
			else if ((alignment == 3) || (alignment == 7)) {
				if (dLength >= 32) {
					RetVal = WaitForSingle(0x20);
                    if (SD_API_FAILED(RetVal)) {
                        goto __Exit;
                    }
					*pBuf					= *pMMC_RX_Fifo;			// 1 Byte
					*(UInt32 *)(pBuf + 1)	= *(volatile UInt32 *)pMMC_RX_Fifo;	// 4 BYTES
					*(UInt32 *)(pBuf + 5)	= *(volatile UInt32 *)pMMC_RX_Fifo;	// 4 BYTES
					*(UInt32 *)(pBuf + 9)	= *(volatile UInt32 *)pMMC_RX_Fifo;	// 4 BYTES
					*(UInt32 *)(pBuf + 0xd)	= *(volatile UInt32 *)pMMC_RX_Fifo;	// 4 BYTES
					*(UInt32 *)(pBuf + 0x11)= *(volatile UInt32 *)pMMC_RX_Fifo;	// 4 BYTES
					*(UInt32 *)(pBuf + 0x15)= *(volatile UInt32 *)pMMC_RX_Fifo;	// 4 BYTES
					*(UInt32 *)(pBuf + 0x19)= *(volatile UInt32 *)pMMC_RX_Fifo;	// 4 BYTES
					*(UInt16 *)(pBuf + 0x1d)= *(volatile UInt16 *)pMMC_RX_Fifo;	// 2 BYTES
					*(pBuf + 0x1f)			= *pMMC_RX_Fifo;			// 1 Byte
					pBuf += 32;
					dLength-= 32;
				}
				else {
				    RetVal = WaitForSingle(0x20);
                    if (SD_API_FAILED(RetVal)) {
                        goto __Exit;
                    }
					while (dLength > 0)	{
						*pBuf++ = *pMMC_RX_Fifo;
						dLength--;
					}
				}
			}
			else if ((alignment == 2) || (alignment == 6)) {
				if (dLength >= 32) {
					RetVal = WaitForSingle(0x20);
                    if (SD_API_FAILED(RetVal)) {
                        goto __Exit;
                    }
					*(UInt16 *)pBuf			= *(volatile UInt16 *)pMMC_RX_Fifo;	// 2 BYTES
					*(UInt32 *)(pBuf + 2)	= *(volatile UInt32 *)pMMC_RX_Fifo;	// 4 BYTES
					*(UInt32 *)(pBuf + 6)	= *(volatile UInt32 *)pMMC_RX_Fifo;	// 4 BYTES
					*(UInt32 *)(pBuf + 0xa)	= *(volatile UInt32 *)pMMC_RX_Fifo;	// 4 BYTES
					*(UInt32 *)(pBuf + 0xe)	= *(volatile UInt32 *)pMMC_RX_Fifo;	// 4 BYTES
					*(UInt32 *)(pBuf + 0x12)= *(volatile UInt32 *)pMMC_RX_Fifo;	// 4 BYTES
					*(UInt32 *)(pBuf + 0x16)= *(volatile UInt32 *)pMMC_RX_Fifo;	// 4 BYTES
					*(UInt32 *)(pBuf + 0x1a)= *(volatile UInt32 *)pMMC_RX_Fifo;	// 4 BYTES
					*(UInt16 *)(pBuf + 0x1e)= *(volatile UInt16 *)pMMC_RX_Fifo;	// 2 BYTES
					pBuf += 32;
					dLength-= 32;

				}
				else {
				    RetVal = WaitForSingle(0x20);
                    if (SD_API_FAILED(RetVal)) {
                        goto __Exit;
                    }
					while (dLength > 0)	{
						*pBuf++ = *pMMC_RX_Fifo;
						dLength--;
					}
				}
			}
			else {
				if (dLength >= 32) {
					RetVal = WaitForSingle(0x20);
                    if (SD_API_FAILED(RetVal)) {
                        goto __Exit;
                    }
					*(UInt32 *) pBuf		= *(volatile UInt32 *)pMMC_RX_Fifo;
					*(UInt32 *)(pBuf + 4)	= *(volatile UInt32 *)pMMC_RX_Fifo;
					*(UInt32 *)(pBuf + 8)	= *(volatile UInt32 *)pMMC_RX_Fifo;
					*(UInt32 *)(pBuf + 0xc) = *(volatile UInt32 *)pMMC_RX_Fifo;
					*(UInt32 *)(pBuf + 0x10)= *(volatile UInt32 *)pMMC_RX_Fifo;
					*(UInt32 *)(pBuf + 0x14)= *(volatile UInt32 *)pMMC_RX_Fifo;
					*(UInt32 *)(pBuf + 0x18)= *(volatile UInt32 *)pMMC_RX_Fifo;
					*(UInt32 *)(pBuf + 0x1C)= *(volatile UInt32 *)pMMC_RX_Fifo;
					pBuf += 32;
					dLength -= 32;

				}
				else {
					RetVal = WaitForSingle(0x20);
                    if (SD_API_FAILED(RetVal)) {
                        goto __Exit;
                    }
					while (dLength > 0)	{
						*pBuf++ = *pMMC_RX_Fifo;
						dLength--;
					}
				}
			}
		}
	}

	m_pvMMCReg->MMC_I_MASK |= 0x20;
    m_pvMMCReg->MMC_I_MASK &= ~0x1;		// Data Transfer Done

    WaitForSingle(0x01);
    m_pvMMCReg->MMC_I_MASK = 0xFF;

__Exit:
//    kprintf("Receive Buffer Content : \n");
//    hexouts(dBuf, dataLength*noBlocks);
	return RetVal;
}


SD_API_STATUS CSDBusDriver::SDCardDataXmit( UInt8 *dBuf,
                                            UInt32 dataLength,
                                            UInt32 noBlocks)
{
    UInt32 dLength, i, align;
    volatile UInt8 *pMMC_TX_Fifo = (volatile UInt8*)&(m_pvMMCReg->MB_TXFIFO);
    UInt8 *pChar = dBuf;
    SD_API_STATUS RetVal = SD_API_STATUS_SUCCESS;
	m_pvMMCReg->MMC_I_MASK &= ~0x40;

    for ( i = 0; i < noBlocks; i++) {
        dLength = dataLength;
		while (dLength) {
		    align = (int)pChar & 0x03;
			if ((align == 1) || (align == 5)) {
				if (dLength >= 32) {
    				RetVal = WaitForSingle(0x40);
                    if (SD_API_FAILED(RetVal)) {
                        goto __Exit;
                    }
                    *pMMC_TX_Fifo           = *pChar;                   // 1 Byte
                    *(volatile UInt16 *)pMMC_TX_Fifo = *(UInt16 *)(pChar + 1);   // 2 Byte
                    *(volatile UInt32 *)pMMC_TX_Fifo = *(UInt32 *)(pChar + 3);   // 4 Byte
                    *(volatile UInt32 *)pMMC_TX_Fifo = *(UInt32 *)(pChar + 7);   // 4 Byte
                    *(volatile UInt32 *)pMMC_TX_Fifo = *(UInt32 *)(pChar + 0xb); // 4 Byte
                    *(volatile UInt32 *)pMMC_TX_Fifo = *(UInt32 *)(pChar + 0xf); // 4 Byte
                    *(volatile UInt32 *)pMMC_TX_Fifo = *(UInt32 *)(pChar + 0x13);// 4 Byte
                    *(volatile UInt32 *)pMMC_TX_Fifo = *(UInt32 *)(pChar + 0x17);// 4 Byte
                    *(volatile UInt32 *)pMMC_TX_Fifo = *(UInt32 *)(pChar + 0x1b);// 4 Byte
                    *pMMC_TX_Fifo           = *(pChar + 0x1f);          // 1 Byte
                    pChar += 32;
                    dLength -= 32;
				}
				else {
    				RetVal = WaitForSingle(0x40);
                    if (SD_API_FAILED(RetVal)) {
                        goto __Exit;
                    }
					while (dLength > 0)	{
						*pMMC_TX_Fifo = *pChar++;
						dLength--;
					}
					m_pvMMCReg->MMC_PRTBUF = XLLP_MMC_PRTBUF;
				}
			}
			else if ((align == 3) || (align == 7)) {
				if (dLength >= 32) {
    				RetVal = WaitForSingle(0x40);
                    if (SD_API_FAILED(RetVal)) {
                        goto __Exit;
                    }
					*pMMC_TX_Fifo           =  *pChar;					   // 1 Byte
					*(volatile UInt32 *)pMMC_TX_Fifo =	*(UInt32 *)(pChar + 1);	   // 4 BYTES
					*(volatile UInt32 *)pMMC_TX_Fifo =	*(UInt32 *)(pChar + 5);	   // 4 BYTES
					*(volatile UInt32 *)pMMC_TX_Fifo =	*(UInt32 *)(pChar + 9);	   // 4 BYTES
					*(volatile UInt32 *)pMMC_TX_Fifo =	*(UInt32 *)(pChar + 0xd);  // 4 BYTES
					*(volatile UInt32 *)pMMC_TX_Fifo =	*(UInt32 *)(pChar + 0x11); // 4 BYTES
					*(volatile UInt32 *)pMMC_TX_Fifo =	*(UInt32 *)(pChar + 0x15); // 4 BYTES
					*(volatile UInt32 *)pMMC_TX_Fifo =	*(UInt32 *)(pChar + 0x19); // 4 BYTES
					*(volatile UInt16 *)pMMC_TX_Fifo =	*(UInt16 *)(pChar + 0x1d); // 2 BYTES
					*pMMC_TX_Fifo           =  *(pChar + 0x1f); 		   // 1 Byte
					pChar += 32;
					dLength-= 32;
				}
				else {
    				RetVal = WaitForSingle(0x40);
                    if (SD_API_FAILED(RetVal)) {
                        goto __Exit;
                    }
  					while (dLength > 0)	{
						*pMMC_TX_Fifo = *pChar++;
						dLength--;
					}
					m_pvMMCReg->MMC_PRTBUF = XLLP_MMC_PRTBUF;
				}
			}
			else if ((align == 2) || (align == 6)) {
				if (dLength >= 32) {
    				RetVal = WaitForSingle(0x40);
                    if (SD_API_FAILED(RetVal)) {
                        goto __Exit;
                    }
					*(volatile UInt16 *)pMMC_TX_Fifo = *(UInt16 *) pChar;		  	// 2 BYTES
					*(volatile UInt32 *)pMMC_TX_Fifo = *(UInt32 *)(pChar + 2);	  	// 4 BYTES
					*(volatile UInt32 *)pMMC_TX_Fifo = *(UInt32 *)(pChar + 6);	  	// 4 BYTES
					*(volatile UInt32 *)pMMC_TX_Fifo = *(UInt32 *)(pChar + 0xa);  	// 4 BYTES
					*(volatile UInt32 *)pMMC_TX_Fifo = *(UInt32 *)(pChar + 0xe);  	// 4 BYTES
					*(volatile UInt32 *)pMMC_TX_Fifo = *(UInt32 *)(pChar + 0x12); 	// 4 BYTES
					*(volatile UInt32 *)pMMC_TX_Fifo = *(UInt32 *)(pChar + 0x16); 	// 4 BYTES
					*(volatile UInt32 *)pMMC_TX_Fifo = *(UInt32 *)(pChar + 0x1a); 	// 4 BYTES
					*(UInt16 *)pMMC_TX_Fifo = *(UInt16 *)(pChar + 0x1e); 	// 2 BYTES
					pChar += 32;
					dLength-= 32;

				}
				else {
    				RetVal = WaitForSingle(0x40);
                    if (SD_API_FAILED(RetVal)) {
                        goto __Exit;
                    }
					while (dLength > 0)	{
						*pMMC_TX_Fifo = *pChar++;
						dLength--;
					}
					m_pvMMCReg->MMC_PRTBUF = XLLP_MMC_PRTBUF;
				}
			}
			else {
				if (dLength >= 32) {
    				RetVal = WaitForSingle(0x40);
                    if (SD_API_FAILED(RetVal)) {
                        goto __Exit;
                    }
					*(volatile UInt32 *)pMMC_TX_Fifo  = *(UInt32 *) pChar;
					*(volatile UInt32 *)pMMC_TX_Fifo  = *(UInt32 *)(pChar + 4);
					*(volatile UInt32 *)pMMC_TX_Fifo  = *(UInt32 *)(pChar + 8);
					*(volatile UInt32 *)pMMC_TX_Fifo  = *(UInt32 *)(pChar + 0xc);
					*(volatile UInt32 *)pMMC_TX_Fifo  = *(UInt32 *)(pChar + 0x10);
					*(volatile UInt32 *)pMMC_TX_Fifo  = *(UInt32 *)(pChar + 0x14);
					*(volatile UInt32 *)pMMC_TX_Fifo  = *(UInt32 *)(pChar + 0x18);
					*(volatile UInt32 *)pMMC_TX_Fifo  = *(UInt32 *)(pChar + 0x1C);
					pChar += 32;
					dLength -= 32;

				}
				else {
    				RetVal = WaitForSingle(0x40);
                    if (SD_API_FAILED(RetVal)) {
                        goto __Exit;
                    }
					while (dLength > 0)	{
						*pMMC_TX_Fifo = *pChar++;
						dLength--;
					}
					m_pvMMCReg->MMC_PRTBUF = XLLP_MMC_PRTBUF;
				}
			}
		}
    } //for
__Exit:
    m_pvMMCReg->MMC_I_MASK |= 0x40;  //disable this tranmit request interrupt
    m_pvMMCReg->MMC_I_MASK &=~0x1;		// Data Transfer Done
    WaitForSingle(0x01);//wait trans complete single
    m_pvMMCReg->MMC_I_MASK |=0x1;
    m_pvMMCReg->MMC_I_MASK &=~0x2;
    WaitForSingle( 0x2);//wait  MMC Prog Done
    m_pvMMCReg->MMC_I_MASK = 0xFF;

	return RetVal;

}



SD_API_STATUS CSDBusDriver::SDCardInfoQuery_X( SD_INFO_TYPE InfoType,
                                               PSD_COMMAND_RESPONSE pResponse,
                                               UInt32 NumBlk,
                                               UInt32 BlkSiz,
                                               UInt8 *pBuff )
{
    SD_API_STATUS  RetVal;
    XLLP_MMC_CMD Cmd;
    UInt32 Arg;
    Boolean IsApp = FALSE;
    switch (InfoType) {
        case SD_INFO_REGISTER_CID:
            if (g_SDCard.SD_RCA == 0x0000) {
                Cmd = XLLP_MMC_CMD2;
                Arg = 0xFFFFFFFF;//don't care;
            }
            else {
                Cmd = XLLP_MMC_SPICMD10;
                Arg   = (UInt32)g_SDCard.SD_RCA;//[31:16]RCA
                Arg <<= 16;
                Arg  |= 0xFFFF;//[15:0]don't care
            }
            pResponse->ResponseType = ResponseR2;
            break;

        case SD_INFO_REGISTER_RCA:
            // RCA is in bytes 3,4
            Cmd = XLLP_MMC_CMD3;
            Arg = 0xFFFFFFFF;//don't care;
            pResponse->ResponseType = ResponseR6;
            break;

        case SD_INFO_REGISTER_OCR:
            if (g_SDCard.SD_RCA == 0x0000) {
                RetVal = SD_API_STATUS_DEVICE_NOT_CONNECTED;
                goto __Exit;
            }
            Cmd = XLLP_MMC_SPICMD1;
            Arg = 0xFFFFFFFF;//don't care;
            break;

        case SD_INFO_REGISTER_CSD:
            if (g_SDCard.SD_RCA == 0x0000) {
                RetVal = SD_API_STATUS_DEVICE_NOT_CONNECTED;
                goto __Exit;
            }
            Cmd = XLLP_MMC_SPICMD9;
            Arg   = (UInt32)g_SDCard.SD_RCA;//[31:16]RCA
            Arg <<= 16;
            Arg  |= 0xFFFF;//[15:0]don't care
            pResponse->ResponseType = ResponseR2;
            break;

        case SD_INFO_REGISTER_SCR://SEND_SCR
            if (g_SDCard.SD_RCA == 0x0000) {
                RetVal = SD_API_STATUS_DEVICE_NOT_CONNECTED;
                goto __Exit;
            }
            Cmd = XLLP_SD_ACMD51;
            Arg   = (UInt32)g_SDCard.SD_RCA;//[31:16]RCA
            Arg <<= 16;
            Arg  |= 0xFFFF;//[15:0]don't care
            pResponse->ResponseType = ResponseR1;
            IsApp = TRUE;
            break;

        case SD_INFO_CARD_STATUS://SEND_STATUS
            if (g_SDCard.SD_RCA == 0x0000) {
                RetVal = SD_API_STATUS_DEVICE_NOT_CONNECTED;
                goto __Exit;
            }
            Cmd = XLLP_MMC_SPICMD13;
            Arg   = 0xFFFFFFFF;//stuff bits
            pResponse->ResponseType = ResponseR1;
            IsApp = TRUE;
            break;

        case SD_INFO_SELECT_BUSWIDTH:
            Cmd = XLLP_SD_ACMD6;
            Arg   = 0xFFFF;//stuff bits
            Arg <<= 16;
            Arg  |= (BlkSiz & 0x0003);//[1:0]BUS WIDTH
            pResponse->ResponseType = ResponseR1;
            IsApp = TRUE;
            break;

        case SD_INFO_SELECT_BLKLENGTH:
            Cmd = XLLP_MMC_SPICMD16;
            Arg = BlkSiz;//[31:0]block length
            pResponse->ResponseType = ResponseR1;
            break;

        default:
           RetVal = SD_API_STATUS_DEVICE_UNSUPPORTED;
           goto __Exit;
    }
    if (IsApp) {
        RetVal = SDCardSendAppCmd_X( Cmd,
                                     Arg,
                                     pResponse,
                                     NumBlk,
                                     BlkSiz,
                                     pBuff);
    }
    else {
        RetVal = SDCardBusRequestAndResponse_X(
                                     Cmd,
                                     Arg,
                                     pResponse,
                                     NumBlk,
                                     BlkSiz,
                                     pBuff);
    }
    if (SD_API_FAILED(RetVal)) {
        DEBUGCHK(_DBGSD, \
        kprintf("SDCardInfoQuery_X InfoType : %08x Failed RetVal : %08x\n",\
                    InfoType, RetVal));
        goto __Exit;
    }
    DEBUGCHK(_SUCSD, \
    kprintf("SDCardInfoQuery_X InfoType : %08x Succeeded RetVal : %08x\n",\
                InfoType, RetVal));

__Exit:
    return RetVal;
}



